/*
 * @Author: dgflash
 * @Date: 2022-06-28 17:57:23
 * @LastEditors: dgflash
 * @LastEditTime: 2022-09-20 10:29:15
 */

import chalk from "chalk";
import { HttpClient, HttpServer, HttpServerOptions, PrefixLogger, WsClient, WsServer, WsServerOptions } from "tsrpc";

import { serviceProto as AccountServiceProto, ServiceType as AccountServiceType } from "../../tsrpc/shared/protocols/AccountServiceProto";
import { serviceProto as HallServiceProto, ServiceType as HallServiceType } from "../../tsrpc/shared/protocols/HallServiceProto";
import { serviceProto as GateServiceProto, ServiceType as GateServiceType } from "../../tsrpc/shared/protocols/GateServiceProto";
import { serviceProto as RoomServiceProto, ServiceType as RoomServiceType } from "../../tsrpc/shared/protocols/RoomServiceProto";

import { Config } from "../config/Config";
import { CommonUtil } from "./CommonUtil";
import { ShareConfig } from "../config/ShareConfig";
import { Security } from "./Security";
import { BaseConf } from "../../tsrpc/shared/protocols/base";

/** TSRPC 客户端、服务器对象工厂 */
export class CommonFactory {
    /** 创建 Http 大厅服务端对象 */
    static createHsHall() {
        var options: Partial<HttpServerOptions<HallServiceType>> = {
            port: parseInt(Config.hall.port),
            json: ShareConfig.json,//
            https: CommonUtil.getCertificate()
        }

        var hs = new HttpServer(HallServiceProto, options);
        this.flowServerApi(hs);
        this.checkAuth(hs);

        return hs;
    }
    // /** HTTP 服务端协议数据加密、解密 */
    private static flowServerApi(hs: HttpServer) {
        if (!ShareConfig.security) return;

        // 在将数据发送到网络之前，通常要进行加密/解密
        hs.flows.preSendDataFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.encrypt(v.data);
            }
            return v;
        });

        // 在处理接收到的数据之前，通常要进行加密/解密
        hs.flows.preRecvDataFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.decrypt(v.data);
            }
            return v;
        });
    }


    /** 创建账号服务器Http客户端连接 */
    static createHcAccount() {
        let url = `${ShareConfig.https ? "https" : "http"}://${Config.account.ip}:${Config.account.port}/`;
        let hc = new HttpClient(AccountServiceProto, { server: url });
        this.flowClientApi(hc);

        return hc;
    }
    /**创建连接网关的http连接 */
    static createHcGate() {
        let url = `${ShareConfig.https ? "https" : "http"}://${Config.gate.ip}:${Config.gate.port}/`;
        let hc = new HttpClient(GateServiceProto, { server: url });
        this.flowClientApi(hc);

        return hc;
    }
    // // /** HTTP 客户端协议数据加密、解密 */
    private static flowClientApi(hc: HttpClient<AccountServiceType>| HttpClient<HallServiceType> | HttpClient<GateServiceType> | HttpClient<RoomServiceType>) {
        if (!ShareConfig.security) return;

        hc.flows.preSendDataFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.encrypt(v.data);
            }
            return v;
        });

        // 在处理接收到的数据之前，通常要进行加密/解密
        hc.flows.preRecvDataFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.decrypt(v.data);
            }
            return v;
        });

    }


    /**
     * 创建 Websocket 大厅服务连接房间服务器的客户端
     * @param serverUrl     房间 Websocket 服务器地址
     * @param server        匹配服务器对象
     * @returns WsClient
     */
    static createWscRoom(ip: string, port:string, server: HttpServer) {
        const url = `${ShareConfig.https ? "wss" : "ws"}://${ip}:${port}/`;
        let wsc = new WsClient(RoomServiceProto, {
            server: url,
            logger: new PrefixLogger({
                logger: server.logger,
                prefixs: [chalk.green(`房间服务器 ${url}`)]
            }),
            heartbeat: {
                interval: ShareConfig.heartbeat_interval,
                timeout: ShareConfig.heartbeat_timeout
            },
            logMsg: Config.room.logMsg
        });
        this.flowClientMsg(wsc);

        return wsc;
    }
    // /** WebSocket 客户端协议数据加密、解密 */
    private static flowClientMsg(wsc: WsClient<RoomServiceType>) {
        if (!ShareConfig.security) return;

        // 发送 Message 之前
        wsc.flows.preSendMsgFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.encrypt(v.data);
            }
            return v;
        });

        // 触发 Message 监听事件之前
        wsc.flows.preRecvMsgFlow.push((v: any) => {
            if (v.data instanceof Uint8Array) {
                v.data = Security.decrypt(v.data);
            }
            return v;
        });
    }

    //检查客户端权限
    /** 检查服务器身份 */
    static checkAuth(server: HttpServer | WsServer) {
        server.flows.preApiCallFlow.push(async call => {
            let conf: BaseConf | undefined = call.service.conf;

            // 执行 API 接口实现之前通过令牌获取当前用户信息
            // let req = call.req as BaseRequest;
            // if (req.__ssoToken) {
            //     call.user = this.parseSSO(req.__ssoToken);
            // }

            // 验证请求客户端地址是否在白名单列表中
            if (conf?.needCheckAddress && (Config.ips as any)[call.conn.ip] == undefined) {
                await call.error('没有访问权限', { code: 'NEED_AUTHORITY' });
                return null;
            }
            // 玩家必须登录才可以访问服务
            // else if (conf?.needLogin && !call.user) {
            //     await call.error('登录后获取访问权限', { code: 'NEED_LOGIN' });
            //     return null;
            // }

            return call;
        });
    }

    

    

    
}